#pragma once

#include <iostream>

namespace state {
    
/// @brief 环境类, 定义了客户感兴趣的接口，维护一个当前状态，并将与状态相关的操作委托给当前状态对象来处理
class AbstractState;
class EnvContext {
public:
    EnvContext();
    void SetState(std::shared_ptr<AbstractState>& state) {
        state_ = state;
    }
    std::shared_ptr<AbstractState>& GetState() {
        return state_;
    }
    void Operation();
    
private:
    std::shared_ptr<AbstractState> state_ = nullptr;
};

/// @brief 抽象状态类, 封装环境对象中的特定状态所对应的行为
class AbstractState {
public:
    virtual ~AbstractState() {}
    virtual void Operation(EnvContext* context) = 0;
};

/// @brief 具体状态类, 实现抽象状态所对应的行为
class ConcreteStateA : public AbstractState {
public:
    virtual void Operation(EnvContext* context);
};
class ConcreteStateB : public AbstractState {
public:
    virtual void Operation(EnvContext* context);
};

EnvContext::EnvContext() {
    state_.reset(new ConcreteStateA()); // 给定初始状态
}

void EnvContext::Operation() {
    state_->Operation(this);
}

void ConcreteStateA::Operation(EnvContext* context) {
    printf("Now Your State is A!\n");
    // 同时改变状态
    std::shared_ptr<AbstractState> new_state(new ConcreteStateB());
    context->SetState(new_state);
}

void ConcreteStateB::Operation(EnvContext* context) {
    printf("Now Your State is B!\n");
    // 同时改变状态
    std::shared_ptr<AbstractState> new_state(new ConcreteStateA());
    context->SetState(new_state);
}

} // namespace state

void Test_17_state_impl_1() {
    printf("-------------------- %s --------------------\n", __FUNCTION__);
    std::shared_ptr<state::EnvContext> ptr(new state::EnvContext());
    ptr->Operation();   // A
    ptr->Operation();   // B
    ptr->Operation();   // A
    ptr->Operation();   // B
}

// -------------------- Test_17_state_impl_1 --------------------
// Now Your State is A!
// Now Your State is B!
// Now Your State is A!
// Now Your State is B!